<template>
  <div class="upload-queue">
    <a-upload multiple accept="image/png, image/jpeg, image/jpg" :showUploadList="false" :max-count="maxCount"
      :before-upload="beforeUpload">
      <a-button type="dashed"><upload-outlined />选择图片</a-button>
    </a-upload>
    <div class="upload-list" v-if="fileList?.length">
      <div class="upload-list-item" v-for="item in fileList">
        <a-image :src="item.url" />
        <span class="close" @click="handleRemove(item.uid)"><close-outlined /></span>
        <span :class="'status status-' + item.status">
          <loading-outlined v-if="item.status === 'uploading'" />
          <check-circle-outlined v-else-if="item.status === 'done'" />
          <close-circle-outlined v-else-if="item.status === 'error'" />
          <clock-circle-outlined v-else />
        </span>
      </div>
    </div>
    <a-divider />
    <a-button type="primary" @click="handleUpload" :loading="loading" :disabled="!fileQueue?.length">开始上传</a-button>
    <div class="a-text-secondary padding-top-md">请上传png/jpg格式图片，10M以内，最多允许上传 {{ maxCount }} 张图片</div>
  </div>
</template>
<script lang="ts" setup>
import { UploadOutlined, CloseOutlined, LoadingOutlined, CloseCircleOutlined, ClockCircleOutlined, CheckCircleOutlined } from '@ant-design/icons-vue';
import { onMounted, ref, type PropType } from 'vue';
import { message } from 'ant-design-vue';
import type { UploadProps } from 'ant-design-vue';
import { uploader } from "@/server/modules/uploader";
import { staticURL } from "@/config";
import { getRandom } from '@/hooks';
import {fetchCsrfToken} from '@/server/modules/uploader'

//文件上传状态
type FileListStatus = 'done' | 'error' | 'uploading' | 'waiting';

//文件渲染列表类型
interface FileList {
  uid: string;
  url: string;
  status: FileListStatus;
}
//文件上传属性
const props = defineProps({
  maxCount: { type: Number, default: 20 },
  value: { type: Array as PropType<string[]>, default: [] },
  multiple: { type: Boolean, default: true },
  listType: { type: String, default: 'picture-card' },
  interval: { type: Number, default: 500 },
});
//响应式数据
const emit = defineEmits(['update:value']);
// 文件渲染列表
const fileList = ref<FileList[]>([]);
// 文件上传列队
const fileQueue = ref<UploadProps['fileList']>([])
const fileQueueIndex = ref<number>(0)
const loading = ref(false);

// 拦截上传，将文件加入队列
const beforeUpload: UploadProps['beforeUpload'] = file => {
  const isLt2M = file.size / 1024 / 1024 < 10;
  if (!isLt2M) {
    message.error('上传图片大小不能超过10M');
    return false;
  }
  // 判断文件类型
  const isJPG = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg';
  if (!isJPG) {
    message.error('上传图片只能是 JPG/PNG/JPEG 格式!');
    return false;
  }
  //加入上传列队
  fileQueue.value = [...(fileQueue.value || []), file];
  //加入预览列队
  fileList.value = [...(fileList.value || []), { uid: file.uid, url: URL.createObjectURL(file), status: 'waiting' }];
  return false; // 阻止默认上传
};

const handleRemove = (item: string) => {
  //删除文件渲染列表
  fileList.value = fileList.value.filter(file => file.uid !== item)
  //删除文件列队
  fileQueue.value = fileQueue.value?.filter(file => file.uid !== item)

  updataValue()
};
const handleUpload = async () => {
  if (fileQueue.value && fileQueue.value.length > 0) {

    const fileLength = fileQueue.value.length
    loading.value = true
    // 遍历文件列队，将每个文件添加到表单数据中
    fileQueue.value.forEach(async (file: any, index: number) => {
      try {
        // 改变文件status为uploading
        updateFileList(file.uid, undefined, 'uploading')
        // 添加表单数据
        const formData = new FormData();
        // 将文件传入表单数据中
        formData.append('file', file);
        // 使用axios上传图片到服务器，计时器间隔1秒*设置间隔
        setTimeout(async () => {
          const res = await uploader(formData)
          if (res.code === 200) {
            // 上传成功 更新文件状态
            updateFileList(file.uid, res.data.file_url, 'done')
            fileQueueIndex.value++
            if(fileQueueIndex.value === fileLength){
              fileQueue.value = []
              // 重置索引
              fileQueueIndex.value = 0
              // 关闭加载
              loading.value = false
              updataValue()
              message.success('上传成功')
            }
          }
        }, index * props.interval)
      } catch (error) {
        // 上传失败 及时更新文件状态
        updateFileList(file.uid, undefined, 'error')
        loading.value = false
      }
    })
  }
};

//更新文件列表状态逻辑
const updateFileList = (uid: string, url?: string, status?: FileListStatus) => {
  fileList.value.forEach(item => {
    if (item.uid === uid) {
      item.url = url ? staticURL + url : item.url
      item.status = status ? status : item.status
    }
  })
}
//更新文件上传值和重置上传状态
const updataValue = () => {
  const value: string[] = []
  fileList.value.forEach(file => {
    if (file.status === 'done') {
      //删除url中的host信息 添加到value中
      value.push(file.url.replace(staticURL, ''))
    }
  })
  emit('update:value', value)
}
//初始挂在 格式化显示列表，用于编辑
onMounted(() => {
  fetchCsrfToken()
  if (props.value && props.value.length) {
    const list: FileList[] = []
    props.value.map((item) => {
      list.push({
        uid: getRandom(),
        url: staticURL + item,
        status: 'done'
      })
    })
    fileList.value = list
  }
})
</script>
<style scoped>
.upload-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 16px 0;
}

.upload-list-item {
  width: 100px;
  height: 100px;
  display: flex;
  justify-content: center;
  text-align: center;
  border: 1px solid #d9d9d9;
  border-radius: 6px;
  background: #f5f5f5;
  position: relative;
  overflow: hidden;
}

.upload-list-item img {
  width: 100%;
  height: auto;
}

.upload-list-item>.close {
  position: absolute;
  display: inline-flex;
  width: 16px;
  height: 16px;
  right: 2px;
  top: 2px;
  text-align: center;
  cursor: pointer;
  justify-content: center;
  border-radius: 4px;
  font-size: 10px;
  background-color: rgba(0, 0, 0, .25);
  color: rgba(255, 255, 255, .75)
}

.upload-list-item>.status {
  position: absolute;
  display: inline-flex;
  width: 16px;
  height: 16px;
  text-align: center;
  cursor: pointer;
  justify-content: center;
  border-radius: 4px;
  font-size: 10px;
  background-color: rgba(0, 0, 0, .25);
  color: rgba(255, 255, 255, .75);
  left: 2px;
  bottom: 2px;
}

.upload-list-item>.close:hover {
  background-color: #ff4d4f;
  color: #fff;
  transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
}

.gallery-upload {
  width: 102px;
  height: 102px;
  overflow: hidden;
  display: block;
}
</style>
